package com.ruoyi.system.task;


import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.config.MinioConfig;
import com.ruoyi.system.domain.ByDb15;
import com.ruoyi.system.mapper.ByExportTaskMapper;
import com.ruoyi.system.service.impl.EsServiceImpl;
import com.ruoyi.system.utils.Md5Utils;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.shaded.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


@Slf4j
public class ByExportFileProcessorWrapper {


    private String author = null;
    //任务总数
//    private Integer taskMount = 0;

    //失败任务总数
    private AtomicInteger failCount = new AtomicInteger(0);
    //累积的任务总数
    private AtomicInteger allCount = new AtomicInteger(1);
    //成功任务总数
    private AtomicInteger successCount = new AtomicInteger(0);

    ByExportProcessor xmlProcessor = null;

//    @Autowired
//    private MinioConfig minioConfig;

//    @Autowired
//    private MinioClient client;

    @Value("${exportPath}")
    private String exportPath;

    public ByExportFileProcessorWrapper() {

    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }



    /**
     * @param userId       提交人
     * @param allCount     zongrenwush8u
     * @param failCount    失败数
     * @param successCount 成功数
     */
    public void init(String userId, AtomicInteger allCount, AtomicInteger successCount, AtomicInteger failCount) {
//        this.taskMount = taskMount;
        this.author = userId;
        this.allCount = allCount;
        this.successCount = successCount;
        this.failCount = failCount;
        xmlProcessor = new ByExportProcessor(userId);
    }

    public String getKeyword() {
        return this.keyword;
    }

    public String keyword;

    public String a101;

    public String a200;

    public String standardType;

    public int taskId;

    public String getA101() {
        return this.a101;
    }
    public String getA200() {
        return this.a200;
    }
    public String getStandardType() {
        return this.standardType;
    }
    public int getTaskId() {
        return this.taskId;
    }

    public void setTaskId(int taskId) {
        this.taskId = taskId;
    }
    public void setA101(String a101) {
        this.a101 = a101;
    }
    public void setA200(String a200) {
        this.a200 = a200;
    }
    public void setStandardType(String standardType) {
        this.standardType = standardType;
    }

    /**
     * 碎片化程序入口
     */
    void execute() {
        long st = System.currentTimeMillis();
        boolean processFrage = false;
        try {
            processFrage = this.process();
        } catch (Exception e) {
            e.printStackTrace();
            failCount.incrementAndGet();
            log.error("题录:{}导出失败-->{}", keyword, e.getMessage());
            log.error(e.getMessage(), e);
        }
        allCount.incrementAndGet();
        log.info("procssing-->{}/{}, cost {}s", allCount.get(), (System.currentTimeMillis() - st) / 1000);
        log.info("本次共导出: 其中成功：{}条，失败：{}条。;", successCount, failCount);
        afterImport();
        log.info("===================题录导出完成=============");

    }

    /**
     * 入库完成后续操作
     */
    void afterImport() {
        //上传完成  更新路径和状态
        try {
//            xmlProcessor.updateImportStatus(materialLibId);
        } catch (Exception e) {
            log.error("删除文件或者更新知识库异常{}", e.getMessage());
            log.error(e.getMessage(), e);
        } finally {
            ByExportTaskMapper byExportTaskMapper = SpringUtils.getBean(ByExportTaskMapper.class);
            byExportTaskMapper.doneTask(taskId,1);
        }
    }

    /**
     * 处理导入逻辑
     *
     * @throws Exception
     */
    public Boolean process() {
        log.info("===================begin to export【" + keyword + "】=============");
        log.info("===================begin to export【" + a101 + "】=============");
        log.info("===================begin to export【" + a200 + "】=============");
        log.info("===================begin to export【" + standardType + "】=============");
        //es查询集合
        EsServiceImpl esService = SpringUtils.getBean(EsServiceImpl.class);
        List<ByDb15> list = esService.searchAll(keyword,a101,a200,standardType);
        //执行导出操作
        log.info("===================handle export【" + list.size() + "】done=============");
        doProcess(xmlProcessor, list, taskId);
        return true;
    }

    /**
     * 处理碎片化的各个环节步骤
     *
     * @param xmlProcessor
     * @param list
     * @throws Exception
     */
    private void doProcess(ByExportProcessor xmlProcessor, List<ByDb15> list, int taskId) {
        //生成excel保存到指定路径 并上传到minio
        List<String> listFileTarget = new ArrayList<>();
//        listFileTarget.add("");
//        listFileTarget.add("");
        log.info("文件导出----------{}",list.size());
        //list 循环文件合并zip
        list.stream().forEach(element -> {
            if(StringUtils.isNotEmpty(element.getFilePath())){
                if(element.getFilePath().startsWith("http")){
                    try {
//                    URL url = new URL(element.getFilePath());
                        String finalPath = RuoYiConfig.getDownloadPath() + element.getA100().replace("/","_") + ".pdf";
                        log.info("下载文件路径------{}",finalPath);
//                    File file = new File(finalPath);
                        //下载minio文件
                        MinioConfig minioConfig = SpringUtils.getBean(MinioConfig.class);
                        MinioClient client = MinioClient.builder().endpoint("http://192.168.1.132:9005").credentials("admin", "12345678").build();
                        String bucketName = minioConfig.getBucketName();
                        String filePath = element.getFilePath();
                        String objectName = filePath.substring(30,filePath.length());
                        InputStream inputStream = client.getObject(GetObjectArgs.builder()
                                .bucket(bucketName)
                                .object(objectName)
                                .build());
                        saveToFile(inputStream,finalPath);

                        listFileTarget.add(finalPath);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        try{
            String zipFilePath = RuoYiConfig.getDownloadPath() + UUID.randomUUID().toString() + ".zip";
//            FileOutputStream fos = new FileOutputStream(zipFilePath);
//            ZipOutputStream zipOut = new ZipOutputStream(fos);
//            for (String srcFile : listFileTarget) {
//                File fileToZip = new File(srcFile);
//                FileInputStream fis = new FileInputStream(fileToZip);
//                ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
//                zipOut.putNextEntry(zipEntry);
//
//                byte[] bytes = new byte[1024];
//                int length;
//                while ((length = fis.read(bytes)) >= 0) {
//                    zipOut.write(bytes, 0, length);
//                }
//                fis.close();
//            }

            compressFilesToZip(listFileTarget.toArray(new String[listFileTarget.size()]),zipFilePath);
            //上传zip到minio
            InputStream inputStream = null;
            InputStream md5Stream = null;
            inputStream = new FileInputStream(zipFilePath);
            md5Stream = new FileInputStream(zipFilePath);

            File file = new File(zipFilePath);
            String fileName = FilenameUtils.getName(zipFilePath);
            // 上传并返回新文件名称
            MinioConfig minioConfig = SpringUtils.getBean(MinioConfig.class);
            MinioClient client = SpringUtils.getBean(MinioClient.class);
            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(fileName)
                    .stream(inputStream, file.length(), -1)
                    .contentType("application/octet-stream")
                    .build();
            client.putObject(args);
            inputStream.close();
            md5Stream.close();

            String url = minioConfig.getReturnUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
            log.info("upload->{} to {}", file.getName(), url);
            //更新文件路径
            ByExportTaskMapper byExportTaskMapper = SpringUtils.getBean(ByExportTaskMapper.class);
            byExportTaskMapper.updateFile(taskId,url);
        }catch (Exception e){
            log.error(e.getMessage());
        }
    }

    public void saveToFile(InputStream inStream, String filePath) throws IOException {
        try (OutputStream outStream = new FileOutputStream(filePath)) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, bytesRead);
            }
        }
    }


    public boolean compressFilesToZip(String[] files,String zipfile) {
        return rugularZip(files,zipfile);
    }

    private boolean rugularZip(String[] fromFiles,String toFile) {
        File zipFile=new File(toFile);
        byte[] buffer=new byte[1024];
        int readLen=0;

        try {
            ZipOutputStream zipOut=new ZipOutputStream(new FileOutputStream(zipFile)) ;

            int index=0;
            for(String file:fromFiles) {
                File fileWillZip=new File(file);

                if(fileWillZip.exists()) {
                    InputStream inputStream=new BufferedInputStream(new FileInputStream(fileWillZip));
                    String entryName="#"+index+"_"+fileWillZip.getName();// entryName should be a valid filename,no path seperater allowed
                    zipOut.putNextEntry(new ZipEntry(entryName));

                    while((readLen=inputStream.read(buffer,0,1024))!=-1) {
                        zipOut.write(buffer,0,readLen);
                    }
                    inputStream.close();

                    index++;
                }
            }

            zipOut.close();
        }catch(Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }




}
